package gdac

import (
	"bytes"
	"database/sql/driver"
	"fmt"
)

type DacStmt struct {
	daclib    *DacLib
	dacconn   uintptr
	dacquery  uintptr
	qryscript string
	nParam    int
}

func (s *DacStmt) checkDac() error {
	if s.dacquery != 0 {
		return nil
	}

	s.dacquery = s.daclib.NewQuery(s.dacconn)
	return nil
}

func (s *DacStmt) prepareCmdText(script string) error {
	n := 0
	strBuf := []byte(script)
	//newBuf := make([]byte, 0, len(script))
	for {
		idx := bytes.IndexByte(strBuf, '?')
		if idx == -1 {
			break
		}
		nameBuf := []byte(fmt.Sprintf(":%d", n))
		strBuf = DeleteBuf(strBuf, idx, 1)
		strBuf = InsertBuf(strBuf, idx, nameBuf)
		n++
	}
	s.qryscript = string(strBuf)
	s.checkDac()
	s.nParam = s.daclib.SetQueryText(s.dacquery, s.qryscript)
	if s.nParam == -1 {
		msg := s.daclib.GetQueryLastErr(s.dacquery)
		return fmt.Errorf("%s", msg)
	}
	return nil
}

func (s *DacStmt) bindArgs(args []driver.Value) error {
	if len(args) == 0 {
		return nil
	}
	s.daclib.SetQueryParams(s.dacquery, args)
	return nil
}

func (s *DacStmt) Query(args []driver.Value) (driver.Rows, error) {
	e1 := s.bindArgs(args)
	if e1 != nil {
		return nil, e1
	}
	n, err := s.daclib.OpenQuery(s.dacquery)
	if err != nil {
		return nil, err
	}
	rval := NewDacDBRows(s.daclib)
	rval.dacquery = s.dacquery
	rval.n = int64(n)
	return rval, nil
	//return &DacDBRows{dacquery: s.dacquery, n: int64(n)}, nil
}

func (s *DacStmt) Exec(args []driver.Value) (driver.Result, error) {
	e1 := s.bindArgs(args)
	if e1 != nil {
		return nil, e1
	}
	n, err := s.daclib.ExecQuery(s.dacquery)
	if err != nil {
		return nil, err
	}
	return &DacDBResult{n: int64(n)}, nil
}

func (s *DacStmt) Close() error {
	if s.dacquery == 0 {
		return nil
	}
	s.daclib.CloseQuery(s.dacquery)
	s.dacquery = 0
	return nil
}

func (s *DacStmt) NumInput() int {
	return s.nParam
}
